﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;

namespace Ymatou.ServiceCenter.Common
{
    public static class StringExtensions
    {
        public static string ToMd5(this string inputString)
        {
            StringBuilder hash = new StringBuilder();
            MD5 md5 = MD5.Create();
            md5.ComputeHash(Encoding.UTF8.GetBytes(inputString))
                  .ToList()
                  .ForEach(b => hash.AppendFormat("{0:x2}", b));
            return hash.ToString();
        }

        public static string Items(this string source, int itemIndex, string separator = ",")
        {
            if (source == null)
            {
                return string.Empty;
            }
            else
            {
                var items = source.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries);
                if (items.Length > itemIndex)
                {
                    return items[itemIndex];
                }
                else
                {
                    return string.Empty;
                }
            }
        }


        public static string IfEmptyOrWhiteSpace(this string value, string defaultValue)
        {
            if (string.IsNullOrWhiteSpace(value))
                return defaultValue;
            else
                return value;
        }

        public static string TrimToMaxLength(this string value, int maxLength)
        {
            return (value == null || value.Length <= maxLength ? value : value.Substring(0, maxLength));
        }

        public static string TrimToMaxLength(this string value, int maxLength, string suffix)
        {
            return (value == null || value.Length <= maxLength ? value : string.Concat(value.Substring(0, maxLength), suffix));
        }


        public static bool Contains(this string inputValue, string comparisonValue, StringComparison comparisonType)
        {
            return (inputValue.IndexOf(comparisonValue, comparisonType) >= 0);
        }

        public static XDocument ToXDocument(this string xml)
        {
            return XDocument.Parse(xml);
        }

        public static XmlDocument ToXmlDOM(this string xml)
        {
            var document = new XmlDocument();
            document.LoadXml(xml);
            return document;
        }


        public static XPathNavigator ToXPath(this string xml)
        {
            var document = new XPathDocument(new StringReader(xml));
            return document.CreateNavigator();
        }

        public static string Reverse(this string value)
        {
            if (string.IsNullOrWhiteSpace(value))
                return value;
            var chars = value.ToCharArray();
            Array.Reverse(chars);
            return new string(chars);
        }

        public static string EnsureStartsWith(this string value, string prefix)
        {
            return value.StartsWith(prefix) ? value : string.Concat(prefix, value);
        }

        public static string EnsureEndsWith(this string value, string suffix)
        {
            return value.EndsWith(suffix) ? value : string.Concat(value, suffix);
        }

        public static bool IsNumeric(this string value)
        {
            float output;
            return float.TryParse(value, out output);
        }

        public static string ExtractDigits(this string value)
        {
            return string.Join(null, Regex.Split(value, "[^\\d]"));
        }

        public static string ConcatWith(this string value, params string[] values)
        {
            return string.Concat(value, string.Concat(values));
        }


        public static string GetBefore(this string value, string x)
        {
            var xPos = value.IndexOf(x);
            return xPos == -1 ? String.Empty : value.Substring(0, xPos);
        }

        public static string GetBetween(this string value, string x, string y)
        {
            var xPos = value.IndexOf(x);
            var yPos = value.LastIndexOf(y);

            if (xPos == -1 || xPos == -1)
                return String.Empty;

            var startIndex = xPos + x.Length;
            return startIndex >= yPos ? String.Empty : value.Substring(startIndex, yPos - startIndex).Trim();
        }

        public static string GetAfter(this string value, string x)
        {
            var xPos = value.LastIndexOf(x);

            if (xPos == -1)
                return String.Empty;

            var startIndex = xPos + x.Length;
            return startIndex >= value.Length ? String.Empty : value.Substring(startIndex).Trim();
        }

        public static string Join<T>(string separator, T[] value)
        {
            if (value == null || value.Length == 0)
                return string.Empty;
            if (separator == null)
                separator = string.Empty;
            Converter<T, string> converter = o => o.ToString();
            return string.Join(separator, Array.ConvertAll(value, converter));
        }

        public static string Remove(this string value, params char[] removeChar)
        {
            var result = value;
            if (!string.IsNullOrEmpty(result) && removeChar != null)
                Array.ForEach(removeChar, c => result = result.Remove(c.ToString()));

            return result;
        }

        public static string Remove(this string value, params string[] strings)
        {
            return strings.Aggregate(value, (current, c) => current.Replace(c, string.Empty));
        }

        public static string ToUpperFirstLetter(this string value)
        {
            if (string.IsNullOrWhiteSpace(value))
                return value;
            char[] valueChars = value.ToCharArray();
            valueChars[0] = char.ToUpper(valueChars[0]);
            return new string(valueChars);
        }

        public static byte[] GetBytes(this string data)
        {
            return Encoding.Default.GetBytes(data);
        }

        public static byte[] GetBytes(this string data, Encoding encoding)
        {
            return encoding.GetBytes(data);
        }

        public static string ToTitleCase(this string value)
        {
            return CultureInfo.CurrentUICulture.TextInfo.ToTitleCase(value);
        }


        public static bool IsMatchingTo(this string value, string regexPattern)
        {
            return IsMatchingTo(value, regexPattern, RegexOptions.None);
        }

        public static bool IsMatchingTo(this string value, string regexPattern, RegexOptions options)
        {
            return Regex.IsMatch(value, regexPattern, options);
        }

        public static string ReplaceWith(this string value, string regexPattern, string replaceValue)
        {
            return ReplaceWith(value, regexPattern, replaceValue, RegexOptions.None);
        }

        public static string ReplaceWith(this string value, string regexPattern, string replaceValue, RegexOptions options)
        {
            return Regex.Replace(value, regexPattern, replaceValue, options);
        }

        public static string ReplaceWith(this string value, string regexPattern, MatchEvaluator evaluator)
        {
            return ReplaceWith(value, regexPattern, RegexOptions.None, evaluator);
        }

        public static string ReplaceWith(this string value, string regexPattern, RegexOptions options, MatchEvaluator evaluator)
        {
            return Regex.Replace(value, regexPattern, evaluator, options);
        }

        public static MatchCollection GetMatches(this string value, string regexPattern)
        {
            return GetMatches(value, regexPattern, RegexOptions.None);
        }

        public static MatchCollection GetMatches(this string value, string regexPattern, RegexOptions options)
        {
            return Regex.Matches(value, regexPattern, options);
        }

        public static IEnumerable<string> GetMatchingValues(this string value, string regexPattern)
        {
            return GetMatchingValues(value, regexPattern, RegexOptions.None);
        }

        public static IEnumerable<string> GetMatchingValues(this string value, string regexPattern, RegexOptions options)
        {
            return from Match match in GetMatches(value, regexPattern, options)
                   where match.Success
                   select match.Value;
        }

        public static string[] Split(this string value, string regexPattern)
        {
            return value.Split(regexPattern, RegexOptions.None);
        }

        public static string[] Split(this string value, string regexPattern, RegexOptions options)
        {
            return Regex.Split(value, regexPattern, options);
        }

        public static string[] GetWords(this string value)
        {
            return value.Split(@"\W");
        }

        public static string GetWordByIndex(this string value, int index)
        {
            var words = value.GetWords();
            if ((index < 0) || (index > words.Length - 1))
                return string.Empty;
            return words[index];
        }

        public static string RemoveAllSpecialCharacters(this string value)
        {
            var sb = new StringBuilder();
            foreach (var c in value.Where(c => (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')))
                sb.Append(c);
            return sb.ToString();
        }

        public static string SpaceOnUpper(this string value)
        {
            return Regex.Replace(value, "([A-Z])(?=[a-z])|(?<=[a-z])([A-Z]|[0-9]+)", " $1$2").TrimStart();
        }

        public static byte[] ToBytes(this string value)
        {
            return value.ToBytes(null);
        }

        public static byte[] ToBytes(this string value, Encoding encoding)
        {
            encoding = (encoding ?? Encoding.Default);
            return encoding.GetBytes(value);
        }

        public static string EncodeBase64(this string value)
        {
            return value.EncodeBase64(null);
        }

        public static string EncodeBase64(this string value, Encoding encoding)
        {
            encoding = (encoding ?? Encoding.UTF8);
            var bytes = encoding.GetBytes(value);
            return Convert.ToBase64String(bytes);
        }

        public static string DecodeBase64(this string encodedValue)
        {
            return encodedValue.DecodeBase64(null);
        }

        public static string DecodeBase64(this string encodedValue, Encoding encoding)
        {
            encoding = (encoding ?? Encoding.UTF8);
            var bytes = Convert.FromBase64String(encodedValue);
            return encoding.GetString(bytes);
        }

        public static string Times(this string str, int times)
        {
            if (string.IsNullOrEmpty(str)) return string.Empty;
            if (times <= 1) return str;

            StringBuilder strfinal = new StringBuilder();
            for (int ndx = 0; ndx < times; ndx++)
                strfinal.Append(str);

            return strfinal.ToString();
        }

        public static string RemoveExtraWhiteSpace(this string source)
        {
            return string.Join(" ", source.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
        }

        public static T GetAppSettingsValue<T>(this string key, T defaultVal = default(T))
        {
            var val = ConfigurationManager.AppSettings[key];
            if (string.IsNullOrEmpty(val)) return defaultVal;
            return val.ConvertTo<T>(defaultVal);

        }
        public static T ConvertTo<T>(this object v, T defVal = default(T))
        {
            if (v == null) return defVal;
            //目标类型
            var type = typeof(T);
            var valueType = v.GetType();
            if (type == typeof(String))
            {
                return (T)((Object)v.ToString());
            }
            else if (type == typeof(TimeSpan))
            {
                TimeSpan ts;
                if (TimeSpan.TryParse(v.ToString(), out ts))
                {
                    return (T)((object)ts);
                }
                else
                {
                    return defVal;
                }
            }
            else if (type == typeof(DateTime))
            {
                if (valueType == typeof(Int64))
                {
                    try
                    {
                        return (T)((Object)Convert.ToDateTime(Convert.ToInt64(v)));
                    }
                    catch
                    {
                        return defVal;
                    }
                }
                if (valueType == typeof(string))
                {
                    try
                    {
                        DateTime tmpTime;
                        if (DateTime.TryParse(v.ToString(), out tmpTime))
                        {
                            return (T)((Object)tmpTime);
                        }
                    }
                    catch
                    {
                        return defVal;
                    }
                }
            }
            else if (type.IsEnum)
            {
                try
                {
                    var flagsAttribute = type.GetCustomAttributes(false).OfType<FlagsAttribute>().SingleOrDefault();
                    if (flagsAttribute != null)
                        return (T)Enum.Parse(type, v.ToString(), true);
                    else
                        return (T)Enum.Parse(type, v.ToString(), true);

                }
                catch
                {

                    return defVal;
                }
            }
            else if (type == typeof(bool))
            {
                if (v.ToString() == "0") return (T)((object)false);
                if (v.ToString() == "1") return (T)((object)true);
                bool b;
                if (bool.TryParse(v.ToString(), out b))
                {
                    return (T)((object)b);
                }
                else
                {
                    return defVal;
                }
            }
            else if (type == typeof(Type))
            {
                try
                {
                    return (T)((Object)Type.GetType(valueType.FullName));
                }
                catch
                {
                    return defVal;
                }
            }
            else if (type == typeof(XmlDocument))
            {
                try
                {
                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.LoadXml(v.ToString());
                    return (T)((Object)xmlDoc);
                }
                catch
                {
                    return defVal;
                }
            }
            try
            {
                return (T)Convert.ChangeType(v, type);
            }
            catch
            {
                return defVal;
            }
        }
    }
}
